package com.example.jobback.util;

import com.example.jobback.config.AuthConfig;
import com.example.jobback.result.Result;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

/**
 * @ClassName: CrossServiceInvoker
 * @Description: 通用的跨服务调用工具类，统一返回 Result<T> 对象
 * @Author: lhb
 * @Date: 2025/5/28
 */
public class CrossServiceInvoker {

    private final AuthConfig authConfig;
    private final RestTemplate restTemplate;

    public CrossServiceInvoker(AuthConfig authConfig, RestTemplate restTemplate) {
        this.authConfig = authConfig;
        this.restTemplate = restTemplate;
    }

    /**
     * @Description: 通用跨服务调用方法（支持 Query Parameters 和 RequestBody）
     * @param url 请求地址
     * @param method HTTP 方法（GET / POST / PUT / DELETE）
     * @param requestBody 请求体（GET 方法可传 null）
     * @param responseType 返回数据类型（如：User.class）
     * @param userId 用户 ID，用于生成 Token
     * @param params  查询参数（用于 GET 或其他方法）
     * @return ResponseEntity<Result<T>> 响应结果
     * @Author lhb
     * @CreateTime 2025/5/28 15:41
     */
    public <T> ResponseEntity<Result<T>> invoke(
            String url,
            HttpMethod method,
            T requestBody,
            Class<T> responseType,
            Long userId,
            Map<String, Object> params
    ) throws Exception {
        try {
            // 1. 构建 Token
            String userIdentity = SecureEncryptionUtil.encrypt(
                    userId.toString(),
                    authConfig.getJwtIdSecret()
            );
            String token = JWTUtil.generateToken(
                    userIdentity,
                    authConfig.getJwtTime(),
                    authConfig.getJwtCrossServiceSecret()
            );

            // 2. 构建带参数的 URL
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
            if (params != null) {
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    builder.queryParam(entry.getKey(), entry.getValue());
                }
            }
            String fullUrl = builder.build().encode().toUriString();

            // 3. 构建请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.add("Authorization", "Bearer " + token);

            // 4. 构建请求实体（GET 不需要 body）
            HttpEntity<T> requestEntity = method == HttpMethod.GET
                    ? (HttpEntity<T>) HttpEntity.EMPTY
                    : new HttpEntity<>(requestBody, headers);

            // 5. 构建泛型类型引用
            Type resultType = new ParameterizedType() {
                @Override
                public Type[] getActualTypeArguments() {
                    return new Type[]{responseType};
                }

                @Override
                public Type getRawType() {
                    return Result.class;
                }

                @Override
                public Type getOwnerType() {
                    return null;
                }
            };

            ParameterizedTypeReference<Result<T>> typeRef = new ParameterizedTypeReference<>() {
                @Override
                public Type getType() {
                    return resultType;
                }
            };

            // 6. 发送请求并返回 ResponseEntity<Result<T>>
            return restTemplate.exchange(fullUrl, method, requestEntity, typeRef);

        } catch (RestClientException e) {
            System.err.println("跨服务调用失败: " + e.getMessage());
            Result<T> errorResult = (Result<T>) Result.error("跨服务调用失败: " + e.getMessage());
            return new ResponseEntity<>(errorResult, HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * @Description: 通用调用方法，直接返回 Result<T> 对象
     * @param url 请求地址
     * @param method HTTP 方法
     * @param requestBody 请求体
     * @param responseType 返回数据类型(看调用接口的Result<T>是什么)
     * @param userId 用户 ID
     * @param params  查询参数
     * @return Result<T> 返回封装的响应结果
     * @Author lhb
     * @CreateTime 2025/5/28 15:43
     */
    public <T> Result<T> invokeAndHandle(
            String url,
            HttpMethod method,
            T requestBody,
            Class<T> responseType,
            Long userId,
            Map<String, Object> params
    ) throws Exception {
        ResponseEntity<Result<T>> response = invoke(url, method, requestBody, responseType, userId, params);
        return response.getBody();
    }
}
